#include "private.h"

static void on_uvtool_async(uv_async_t* handle) {
    uvtool_t *uvtool = (uvtool_t*)handle->data;
    uvtool_async_t *tmp, *done;
    uv_mutex_lock(&uvtool->uv_mutex);
    tmp = uvtool->async_event_list;
    uvtool->async_event_list = NULL;
    uvtool->async_event_tail = NULL;
    uv_mutex_unlock(&uvtool->uv_mutex);
    while(tmp) {
        if(tmp->cb)
            tmp->cb(tmp->uvtool);
        done = tmp;
        tmp = tmp->next;
        free(done);
    }
}

static void uvtool_init_member(uvtool_t *uvtool) {
    uvtool->uv_async.data = uvtool;
    uv_async_init(uvtool->uv, &uvtool->uv_async, on_uvtool_async);
    uv_mutex_init(&uvtool->uv_mutex);
}

static void uvloopthread(void *arg) {
    uvtool_t *uvtool = (uvtool_t*)arg;
    uvtool->uv = (uv_loop_t *)calloc(1, sizeof(uv_loop_t));
    uv_loop_init(uvtool->uv);
    uvtool_init_member(uvtool);
    while (!uvtool->stop) {
        uv_run(uvtool->uv, UV_RUN_DEFAULT);
    }
    uv_loop_close(uvtool->uv);
    free(uvtool->uv);
    free(uvtool);
}

uvtool_t*  uvtool_init(void *uv) {
    SAFE_MALLOC(uvtool_t, uvtool);
    uvtool->stop = false;
    if(uv) {
        uvtool->thread = false;
        uvtool->uv = (uv_loop_t *)uv;
        uvtool_init_member(uvtool);
    } else {
        uv_thread_t th;
        uvtool->thread = true;
        uv_thread_create(&th, uvloopthread, uvtool);
    }
    return uvtool;
}

void uvtool_clean(uvtool_t* uvtool) {
    uvtool->stop = true;
    uv_stop(uvtool->uv);
    if(!uvtool->thread) {
        free(uvtool);
    }
}

void uvtool_async(uvtool_t* uvtool, uvtool_async_cb cb) {
    SAFE_MALLOC(uvtool_async_t, async_event);
    async_event->uvtool = uvtool;
    async_event->cb = cb;
    uv_mutex_lock(&uvtool->uv_mutex);
    if(uvtool->async_event_tail == NULL) {
        uvtool->async_event_list = async_event;
        uvtool->async_event_tail = async_event;
    } else {
        uvtool->async_event_tail->next = async_event;
    }
    uv_mutex_unlock(&uvtool->uv_mutex);
    uv_async_send(&uvtool->uv_async);
}